
#include "xsapi.h"
#include "xssasl.h"
#include "xsstun.h"

#define	XS_MSG_ID_SIZE	32

char g_cInitFalg = 0;
unsigned char g_aucMsgId[XS_MSG_ID_SIZE] = {0};
static int    gs_iRand = 0;


static int check_xmpp_xml(unsigned char *pucTag, unsigned char *pucData, unsigned int uiLen, unsigned char **pucStazaData, unsigned int *puiStazaLen);
static int get_challenge_text(unsigned char *pcResData, unsigned int uiLen);
static int get_xmpp_message(xsMsg_t *pstMsg, unsigned char *pucInData, unsigned int uiLen);
static int get_xmpp_presence(xsPre_t *pstPre, unsigned char *pucInData, unsigned int uiInLen);
static int get_lomo_cmd(xsPre_t *pstPre, xsUserCfg_t *pstCfg, unsigned char *pucInData, unsigned int uiInLen);

static int xmpp_open_xml(xsCtx_t *pstCtx);
static int xmpp_opening_stream(xsCtx_t *pstCtx);
static int xmpp_set_mode(xsCtx_t *pstCtx);
static int xmpp_md5_auth(xsCtx_t *pstCtx);
static int xmpp_ssl_auth(xsCtx_t *pstCtx);
static int xmpp_binding(xsCtx_t *pstCtx);
static int xmpp_start_session(xsCtx_t *pstCtx);

int xsInit(xsCtx_t *pstCtx)
{	
	int iRet = XS_PARA_ERR;
	if(!pstCtx){
		return iRet;
	}
	if(!pstCtx->pfTcpRecv || !pstCtx->pfTcpSend ){
		return iRet;
	}
	if(!pstCtx->pucSBuf || !pstCtx->pucRBuf || !pstCtx->pcDomain || !pstCtx->pcNode || !pstCtx->pcRes || !pstCtx->pcPwd){
		return iRet;
	}
	if(pstCtx->uiSsize < 1024 || pstCtx->uiRSize < 1024){
		xs_print("ERROR R/S buffer are less than 1024 !\n");
		return iRet;
	}
	iRet = XS_OK;
	if(XS_OK == iRet){
		g_cInitFalg = 1;
	}
  pstCtx->ucStep = XC_OPEN_XML;
	return iRet;
}

int xsXmppLogin(xsCtx_t *pstCtx)
{
	int iRet = XS_FAILURE;

	if(1 != g_cInitFalg || !pstCtx){
		return XS_PARA_ERR;
	}
	switch(pstCtx->ucStep){
		case XC_OPEN_XML:
      iRet = xmpp_open_xml(pstCtx);
      if(XS_OK == iRet){
				pstCtx->ucStep = XC_OPEN_STREAM;
        pstCtx->ucNextStep = XC_SET_MODE;
			}
      break;
		case XC_OPEN_STREAM:
      iRet = xmpp_opening_stream(pstCtx);
			if(XS_OK == iRet){
				pstCtx->ucStep = pstCtx->ucNextStep;
			}
			break;
		case XC_SET_MODE:
			iRet = xmpp_set_mode(pstCtx);
			if(XS_OK == iRet){
				if(XS_MD5_MODE == pstCtx->ucSSL){
					pstCtx->ucStep = XC_MD5_AUTH;
				}else{
					pstCtx->ucStep = XC_TLS_HANDSHAKE;
				}
			}
			break;
		case XC_MD5_AUTH:
			iRet = xmpp_md5_auth(pstCtx);
			if(XS_OK == iRet){
				pstCtx->ucStep = XC_OPEN_STREAM;
        pstCtx->ucNextStep = XC_BINDING;
			}
			break;
		case XC_TLS_AUTH:
			iRet = xmpp_ssl_auth(pstCtx);
			if(XS_OK == iRet){
				pstCtx->ucStep = XC_OPEN_STREAM;
        pstCtx->ucNextStep = XC_BINDING;
			}
			break;
		case XC_BINDING:
			iRet = xmpp_binding(pstCtx);
			if(XS_OK == iRet){
				pstCtx->ucStep = XC_SESSION;
			}
			break;
		case XC_SESSION:
			iRet = xmpp_start_session(pstCtx);
			if(XS_OK == iRet){
				pstCtx->ucStep = XC_HEARTBEAT;
        pstCtx->ucNextStep = XC_HEARTBEAT;
        iRet = XS_XML_LOGIN_SUCCESS;
			}
			break;
		case XC_TLS_HANDSHAKE:
      iRet = XS_CONTINUE;
			break;
		default :
			break;
	}
	return iRet;
}

int xsXmppSendRawString(xsCtx_t *pstCtx, const unsigned char *pcData, unsigned int uiLen)
{
	int iRet = XS_FAILURE;
	if(1 != g_cInitFalg || !pstCtx){
		iRet = XS_PARA_ERR;
		return iRet;
	}
	iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pcData, uiLen);	
  if(0 < iRet){
    iRet = XS_OK;
  }else{
    iRet = XS_CONTINUE;
  }
	return iRet;

}

int xsXmppSendMsg(xsCtx_t *pstCtx, xsMsg_t *pstMsg)
{
	int iRet = XS_FAILURE;
	unsigned int iDLen = 0, i = 0;
	char acEscapeBuf[7] = {0};
  static unsigned char s_uiStep = 0;
	if(1 != g_cInitFalg || !pstCtx || !pstMsg){
		iRet = XS_PARA_ERR;
		return iRet;
	}
  switch(s_uiStep){
    case 0:
      if(0 == g_aucMsgId[1]){
    		gs_iRand++;
    		srand(gs_iRand);
    		snprintf((char *)g_aucMsgId, XS_MSG_ID_SIZE, "lomo_%d", rand());
    	}
    	//xs_print("In:%s[%d]\n", pstMsg->aucMsgData, pstMsg->uiMsgLen);
    	memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
    	snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, "<message type='chat' id='%s' to='%s'><body>", g_aucMsgId, pstMsg->aucJid);
    	iDLen = strlen((char *)pstCtx->pucSBuf);
    	for(i=0; i<pstMsg->uiMsgLen && iDLen < pstCtx->uiSsize-20; i++){
    		switch(pstMsg->aucMsgData[i]){
    			case '<':
    				snprintf(acEscapeBuf, 7,"&lt;");
    				break;
    			case '>':
    				snprintf(acEscapeBuf, 7,"&gt;");
    				break;
    			case '&':
    				snprintf(acEscapeBuf, 7,"&amp;");
    				break;
    			case '\'':
    				snprintf(acEscapeBuf, 7,"&apos;");
    				break;
    			case '"':
    				snprintf(acEscapeBuf, 7,"&quot;");
    				break;
    			default:
    				snprintf(acEscapeBuf, 7,"%c", pstMsg->aucMsgData[i]);
    				break;
    		}
    		snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "%s",acEscapeBuf);
    		iDLen += strlen(acEscapeBuf);
        memset(acEscapeBuf, 0, sizeof(acEscapeBuf));
    	}
    	
    	snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "</body></message>");
      memset(g_aucMsgId, 0, XS_MSG_ID_SIZE);
      s_uiStep = 1;
      iRet = XS_CONTINUE;
      //xs_print("Send:%s\n", pstCtx->pucSBuf);
    case 1:
      iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
    	if(0 < iRet){
        s_uiStep = 0;
        iRet = XS_OK;
      }else{
        iRet = XS_CONTINUE;
      }
      break;
  }
	if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
	}
	return iRet;

}

int xsXmppSendPre(xsCtx_t *pstCtx, const char *pcJID, const unsigned char *pcState)
{
  int iRet = XS_FAILURE;
  unsigned int iDLen = 0;

  static unsigned char s_uiStep = 0;
  if(1 != g_cInitFalg || !pstCtx){
    iRet = XS_PARA_ERR;
    return iRet;
  }
  switch(s_uiStep){
    case 0:
      if(0 == g_aucMsgId[1]){
        gs_iRand++;
        srand(gs_iRand);
        snprintf((char *)g_aucMsgId, XS_MSG_ID_SIZE, "lomo_%d", rand());
      }
      
      memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
      snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, "<presence id='%s' ", g_aucMsgId);
      iDLen = strlen((char *)pstCtx->pucSBuf);
      if(pcJID){
        snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "to='%s'", pcJID);
      }

      iDLen = strlen((char *)pstCtx->pucSBuf);
      snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "><status >%s</status>", pcState);

      iDLen = strlen((char *)pstCtx->pucSBuf);
      snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "</presence>");
      memset(g_aucMsgId, 0, XS_MSG_ID_SIZE);
      s_uiStep = 1;
      iRet = XS_CONTINUE;
    case 1:
      iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 < iRet){
        iRet = XS_OK;
      }else{
        iRet = XS_CONTINUE;
      }
      break;
  }
  if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
	}
  return iRet;

}

int xsXmppSendcmd(xsCtx_t *pstCtx, const char *pcJID, unsigned char ucCmd, const char *pcValue)
{
  int iRet = XS_FAILURE;
  unsigned int iDLen = 0;

  static unsigned char s_uiStep = 0;
  if(1 != g_cInitFalg || !pstCtx){
    iRet = XS_PARA_ERR;
    return iRet;
  }
  switch(s_uiStep){
    case 0:
      if(0 == g_aucMsgId[1]){
        gs_iRand++;
        srand(gs_iRand);
        snprintf((char *)g_aucMsgId, XS_MSG_ID_SIZE, "lomo_%d", rand());
      }
      
      memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
      snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, "<presence id='%s' ", g_aucMsgId);
      iDLen = strlen((char *)pstCtx->pucSBuf);
      if(pcJID){
        snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "to='%s'", pcJID);
      }
      iDLen = strlen((char *)pstCtx->pucSBuf);
      snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "><cmd xmlns='%s'>%d</cmd>", XS_PRI_NS_CMD, ucCmd);

      iDLen = strlen((char *)pstCtx->pucSBuf);
      snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "<status >%s</status>", pcValue);

      iDLen = strlen((char *)pstCtx->pucSBuf);
      snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "</presence>");
      memset(g_aucMsgId, 0, XS_MSG_ID_SIZE);
      s_uiStep = 1;
      iRet = XS_CONTINUE;
    case 1:
      iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 < iRet){
        s_uiStep = 0;
        iRet = XS_OK;
      }else{
        iRet = XS_CONTINUE;
      }
      break;
  }
  if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
	}
  return iRet;

}

int xsXmppSendRes(xsCtx_t *pstCtx, const char *pcJID, unsigned char ucState)
{
  int iRet = XS_FAILURE;
  unsigned int iDLen = 0;

  static unsigned char s_uiStep = 0;
  if(1 != g_cInitFalg || !pstCtx){
    iRet = XS_PARA_ERR;
    return iRet;
  }
  switch(s_uiStep){
    case 0:
      if(0 == g_aucMsgId[1]){
        gs_iRand++;
        srand(gs_iRand);
        snprintf((char *)g_aucMsgId, XS_MSG_ID_SIZE, "lomo_%d", rand());
      }
      
      memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
      snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, "<presence id='%s' ", g_aucMsgId);
      iDLen = strlen((char *)pstCtx->pucSBuf);
      if(pcJID){
        snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "to='%s'", pcJID);
      }
      
      iDLen = strlen((char *)pstCtx->pucSBuf);
      snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "><status >%s</status>", (0 == ucState)? "OK":"Err");

      iDLen = strlen((char *)pstCtx->pucSBuf);
      snprintf((char *)pstCtx->pucSBuf+iDLen, pstCtx->uiSsize-iDLen, "</presence>");
      s_uiStep = 1;
      iRet = XS_CONTINUE;
      xs_print("RES:%s[%d]\n", pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
    case 1:
      iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 < iRet){
        s_uiStep = 0;
        iRet = XS_OK;
      }else{
        iRet = XS_CONTINUE;
      }
      break;
  }
  if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
	}
  return iRet;

}

const char acMsgTag[][9] = {{8}, {"<message"}};
const char acPreTag[][10] = {{9}, {"<presence"}};
const char acLogoutStream[][17] = {{16}, {"</stream:stream>"}};

int xsXmppConnProc(xsCtx_t *pstCtx, xsMsg_t *pstMsg, xsPre_t *pstPre, xsUserCfg_t *pstCfg)
{
  int iRet = XS_OK;
  unsigned char *pucNextPos = 0;
	unsigned int   uiNextLen = 0;
  unsigned char  aucTag[32] = {0};
  
  static int iMuxFalg = 0;
  
  if(1 != g_cInitFalg || !pstCtx){
    iRet = XS_PARA_ERR;
    goto clear_up;
  }

  if(XS_XML_MUX_PACKAGE != iMuxFalg){
    if(pstCtx->uiRSize <= pstCtx->uiRLen){
      iRet = XS_MEM_ERR;
    }else{
      iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL, pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
    }
  }else{
    iRet = pstCtx->uiRLen;
    pstCtx->uiRLen = 0;
    iMuxFalg = 0;
  }

  if(0 < iRet){
    pstCtx->uiRLen += iRet;
    
    if(acLogoutStream[0][0] > pstCtx->uiRLen){
  		iRet = XS_XML_NOT_COMPLETE;
      goto clear_up;
  	}
    
    if(0 != strstr((char *)pstCtx->pucRBuf, acLogoutStream[1])){
      iRet = XS_XML_LOGOUT;
      goto clear_up;
    }
    
    iRet = check_xmpp_xml(aucTag, pstCtx->pucRBuf, pstCtx->uiRLen, &pucNextPos, &uiNextLen);
    if(XS_OK == iRet || XS_XML_MUX_PACKAGE == iRet){
      if(0 == strcmp(acMsgTag[1], (char *)aucTag)){

        if(0 != strstr((char *)pstCtx->pucRBuf, XS_PRI_NS_CMD)){
          iRet = get_lomo_cmd(pstPre, pstCfg, pstCtx->pucRBuf, pstCtx->uiRLen-uiNextLen);
        }else if(0 != strstr((char *)pstCtx->pucRBuf, "</body>")){
          iRet = get_xmpp_message(pstMsg, pstCtx->pucRBuf, pstCtx->uiRLen-uiNextLen);
        }

      }else if(0 == strcmp(acPreTag[1], (char *)aucTag)){
          iRet = get_xmpp_presence(pstPre, pstCtx->pucRBuf, pstCtx->uiRLen-uiNextLen);
      }
		}
    
    if(XS_XML_MUX_PACKAGE == iRet){
      memcpy(pstCtx->pucRBuf, pucNextPos, uiNextLen);
      pstCtx->uiRLen = uiNextLen;
      iMuxFalg = XS_XML_MUX_PACKAGE;
    }
  }else if(0 > iRet){
    iRet = XS_FAILURE;
  }
  clear_up:
  if(0 > iRet || XS_OK == iRet){
    iMuxFalg = 0;
    pstCtx->uiRLen = 0;
    memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
  }
  return iRet;
}


int xsStunProc(xsCtx_t *pstCtx, xsNatAttr_t *pstNatAttr)
{
	int iRet = XS_FAILURE;
	static char cSflag = 0;
	static StunAddressInfo stLocalAddress;
	if(1 != g_cInitFalg || !pstCtx || !pstNatAttr ){
		iRet = XS_PARA_ERR;
		goto clear_up;
	}
	
	if(0 == pstNatAttr->uiDstIp || 0 == pstNatAttr->usDstPort){
		iRet = XS_PARA_ERR;
		goto clear_up;
	}
	if(0 == cSflag){
		memset(&stLocalAddress, 0, sizeof(StunAddressInfo));
		cSflag = 1;
	}
	iRet = GetMapAddr(pstCtx, &stLocalAddress, pstNatAttr->uiSrcIp, pstNatAttr->uiDstIp, pstNatAttr->usDstPort);
	if(XS_OK == iRet){
		pstNatAttr->ucType = stLocalAddress.cNatType;
		memcpy(pstNatAttr->aucMapIp, stLocalAddress.acMappedAddress, 20);
		pstNatAttr->uiMapIp = stLocalAddress.iHexMapip;
		pstNatAttr->usMapPort = stLocalAddress.iMappePort;
		cSflag = 0;
	}else if(XS_FAILURE == iRet){
			cSflag = 0;
	}
	clear_up:
	return iRet;

}

int xsXmppLogout(xsCtx_t *pstCtx)
{
	int iRet = XS_FAILURE;
	if(1 != g_cInitFalg || !pstCtx){
		goto clear_up;
	}
	memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
	snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, "</stream:stream>");
	iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));	
	if(0 < iRet){
    iRet = XS_OK;
  }else{
    iRet = XS_FAILURE;
  }
	clear_up:
	return iRet;

}

int xsTerm(xsCtx_t *pstCtx)
{
	int iRet = XS_FAILURE;
	if(1 != g_cInitFalg){
		goto clear_up;
	}
	g_cInitFalg = 0;
	iRet = XS_OK;
	
	clear_up:
	return iRet;

}

static int xmpp_open_xml(xsCtx_t *pstCtx)
{
  int iRet = XS_FAILURE;
  static int s_uiStep = 0;
  switch(s_uiStep){
    case 0:
      memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
	    snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, "<?xml version='1.0' ?>");
      s_uiStep = 1;
      iRet = XS_CONTINUE;
    case 1:
      iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 > iRet){
        if(XS_TCP_BUSY == iRet){
          iRet = XS_CONTINUE;
        }else{
          s_uiStep = 0;
          iRet = XS_FAILURE;
        }
      }else if(0 < iRet){
        s_uiStep = 0;
        iRet = XS_OK;
      }
      break;
  }
  if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
	}
  return iRet;
}

static int xmpp_opening_stream(xsCtx_t *pstCtx)
{
	static int s_uiStep = 0;
	static int iMuxFalg = 0;
	int iRet = XS_FAILURE;

	unsigned char *pucNextPos = 0;
	unsigned int	 uiNextLen = 0;
	
	switch(s_uiStep){
		case 0:
			memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
      memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
			snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, \
				"<stream:stream to='%s' xml:lang='en' version='1.0' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>",\
				pstCtx->pcDomain);
			s_uiStep = 1;
      pstCtx->uiRLen = 0;
      iRet = XS_CONTINUE;
    case 1:
      iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));      
      if(0 > iRet){
        if(XS_TCP_BUSY == iRet){
          iRet = XS_CONTINUE;
        }else{
          iRet = XS_FAILURE;
        }
      }else if(0 < iRet){
        s_uiStep = 2;
        iRet = XS_CONTINUE;
      }
      break;
		case 2: // R <stream:features>
			if(XS_XML_MUX_PACKAGE != iMuxFalg){
				iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL, pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
      }else{
				iRet = pstCtx->uiRLen;
				pstCtx->uiRLen = 0;
        iMuxFalg = 0;
			}
			if(0 < iRet){
				pstCtx->uiRLen += iRet;
				iRet = check_xmpp_xml(0, pstCtx->pucRBuf, pstCtx->uiRLen, &pucNextPos, &uiNextLen);
				if(XS_OK == iRet || XS_XML_MUX_PACKAGE == iRet){
					if(0 != strstr((char *)pstCtx->pucRBuf, "</stream:features>")){
            if(0 == pstCtx->ucSSL){
              if(0 != strstr((char *)pstCtx->pucRBuf, "starttls ")){
    						pstCtx->ucSSL = XS_TLS_MODE;
    					}else{
    						pstCtx->ucSSL = XS_MD5_MODE;
    					}
            }
						iRet = XS_OK;
            break;
					}
          if(XS_XML_MUX_PACKAGE == iRet){
    				memcpy(pstCtx->pucRBuf, pucNextPos, uiNextLen);
    				memset(pstCtx->pucRBuf+uiNextLen, 0, pstCtx->uiRSize-uiNextLen);
    				pstCtx->uiRLen = uiNextLen;
    				iMuxFalg = XS_XML_MUX_PACKAGE;
    			}
          if(XS_OK == iRet){
            pstCtx->uiRLen = 0;
            memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
          }
          iRet = XS_CONTINUE;
				}
			}else if(XS_TCP_BUSY == iRet){
				iRet = XS_CONTINUE;
			}else{
				iRet = XS_FAILURE;
			}
			break;
	}
	if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
		iMuxFalg = 0;
    pstCtx->uiRLen = 0;
    memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
	}
	return iRet;
}

static int xmpp_set_mode(xsCtx_t *pstCtx)
{
 	static int s_uiStep = 0;

	int iRet = XS_FAILURE;

  unsigned char *pucNextPos = 0;
	unsigned int   uiNextLen = 0;
  
	switch(s_uiStep){
		case 0:
      memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
			if(XS_MD5_MODE == pstCtx->ucSSL){
				snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, \
								"<auth mechanism='DIGEST-MD5' xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
			}else if(XS_TLS_MODE == pstCtx->ucSSL){
				snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, \
								"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
			}
      s_uiStep = 1;
      iRet = XS_CONTINUE;
    case 1:
			iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 > iRet){
        if(XS_TCP_BUSY == iRet){
          iRet = XS_CONTINUE;
        }else{
          iRet = XS_FAILURE;
        }
      }else if(0 < iRet){
        if(XS_TLS_MODE == pstCtx->ucSSL){
          s_uiStep = 2;
					iRet = XS_CONTINUE;
			  }else{
          iRet = XS_OK;
        }
      }
			break;
		case 2:
			iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL,pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
			if(0 < iRet){
				pstCtx->uiRLen += iRet;

				iRet = check_xmpp_xml(0, pstCtx->pucRBuf, pstCtx->uiRLen, &pucNextPos, &uiNextLen);
				if(XS_OK == iRet || XS_XML_MUX_PACKAGE == iRet){
					if(0 != strstr((char *)pstCtx->pucRBuf, "<proceed ")){
            iRet = XS_OK;
            pstCtx->ucSSL = XS_SSL_ENABLE;
          }else{
            iRet = XS_XML_LOGIN_FAILURE;
          }
				}
			}else if(XS_TCP_BUSY == iRet){
				iRet = XS_CONTINUE;
			}else{
				iRet = XS_FAILURE;
			}
			break;
	}
  if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    pstCtx->uiRLen = 0;
    memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
	}
	return iRet;
}

static int xmpp_md5_auth(xsCtx_t *pstCtx)
{
	static int s_uiStep = 0;
	char *response;
	int iRet = XS_FAILURE;

	unsigned char *pucNextPos = 0;
	unsigned int   uiNextLen = 0, uiChallengeText = 0;
	
	switch(s_uiStep){
		case 0:
			memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
			s_uiStep = 1;
			iRet = XS_CONTINUE;
		case 1:
			iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL,pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
			if(0 < iRet){
				pstCtx->uiRLen += iRet;

				iRet = check_xmpp_xml(0, pstCtx->pucRBuf, pstCtx->uiRLen, &pucNextPos, &uiNextLen);
				if(XS_OK == iRet || XS_XML_MUX_PACKAGE == iRet){
					uiChallengeText = get_challenge_text(pstCtx->pucRBuf, pstCtx->uiRLen);
					if(0 < uiChallengeText){
						s_uiStep = 2;
			      iRet = XS_CONTINUE;
					}else{
						iRet = XS_XML_LOGIN_FAILURE;
					}
				}
			}else if(XS_TCP_BUSY == iRet){
				iRet = XS_CONTINUE;
			}else{
				iRet = XS_FAILURE;
			}
			break;
		case 2:
			response = sasl_digest_md5((char *)pstCtx->pucRBuf, (char *)pstCtx->pcNode, (char *)pstCtx->pcDomain, (char *)pstCtx->pcPwd);
			if(response){
				memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
				snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, \
					"<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">%s</response>", response);
        s_uiStep = 3;
        iRet = XS_CONTINUE;
    case 3:
        iRet = pstCtx->pfTcpSend(pstCtx->ucSSL,pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
        if(0 > iRet){
          if(XS_TCP_BUSY == iRet){
            iRet = XS_CONTINUE;
          }else{
            iRet = XS_FAILURE;
          }
        }else if(0 < iRet){
          s_uiStep = 4;
          iRet = XS_CONTINUE;
          pstCtx->uiRLen = 0;
          memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
        }
				#ifndef NO_OS
				xs_free(response);
				#endif
				pstCtx->uiRLen = 0;
			}else{
				iRet = XS_FAILURE;
			}
			break;
		case 4:
			iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL,pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
			if(0 < iRet){
				pstCtx->uiRLen += iRet;

				iRet = check_xmpp_xml(0, pstCtx->pucRBuf, pstCtx->uiRLen, &pucNextPos, &uiNextLen);
				if(XS_OK == iRet || XS_XML_MUX_PACKAGE == iRet){
					if(0 != strstr((char *)pstCtx->pucRBuf, "</success>")){
						iRet = XS_OK;
						xs_print("digest-md5 (rspauth) called for success\n\rSASL DIGEST-MD5 auth successful\n");
					}else{
						iRet = XS_XML_AUTH_FAILURE;
					}
				}
			}else if(XS_TCP_BUSY == iRet){
				iRet = XS_CONTINUE;
			}else{
				iRet = XS_FAILURE;
			}
			break;
	}
	if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    pstCtx->uiRLen = 0;
    memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
	}
	return iRet;
}

static int xmpp_ssl_auth(xsCtx_t *pstCtx)
{
	static int s_uiStep = 0;

	int iRet = XS_FAILURE;
	unsigned char Plaintext[64] = {0};
	char *pciphertext = 0;
	size_t iPlaintextLen = 0;
	unsigned char *pucNextPos = 0;
	unsigned int   uiNextLen = 0;
	
	switch(s_uiStep){
		case 0:
			iPlaintextLen = 1;
			memcpy(Plaintext+iPlaintextLen, pstCtx->pcNode, strlen(pstCtx->pcNode));
			iPlaintextLen += (strlen(pstCtx->pcNode)+1);
			memcpy(Plaintext+iPlaintextLen, pstCtx->pcPwd, strlen(pstCtx->pcPwd));
			iPlaintextLen += strlen(pstCtx->pcPwd);
			
			pciphertext = xs_base64_encode((const unsigned char *)Plaintext, iPlaintextLen);
			memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
			snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, \
				"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN' xmlns:ga='http://www.google.com/talk/protocol/auth' ga:client-uses-full-bind-result='true'>%s</auth>", pciphertext);
      s_uiStep = 1;
      iRet = XS_CONTINUE;
    case 1:
      iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 > iRet){
        if(XS_TCP_BUSY == iRet){
          iRet = XS_CONTINUE;
        }else{
          iRet = XS_FAILURE;
        }
      }else if(0 < iRet){
        s_uiStep = 2;
        iRet = XS_CONTINUE;
      }
			break;
		case 2:
			iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL, pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
			if(0 < iRet){
				pstCtx->uiRLen += iRet;
        
				iRet = check_xmpp_xml(0, pstCtx->pucRBuf, pstCtx->uiRLen, &pucNextPos, &uiNextLen);
				if(XS_OK == iRet || XS_XML_MUX_PACKAGE == iRet){
					if(0 != strstr((char *)pstCtx->pucRBuf, "<success ")){
						iRet = XS_OK;
					}else{
						iRet = XS_XML_AUTH_FAILURE;
					}
				}
			}else if(XS_TCP_BUSY == iRet){
				iRet = XS_CONTINUE;
			}else{
				iRet = XS_FAILURE;
			}
			break;
	}
	if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    pstCtx->uiRLen = 0;
    memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
	}
	return iRet;
}

static int xmpp_binding(xsCtx_t *pstCtx)
{
	static int s_uiStep = 0;
	int iRet = XS_FAILURE;

	unsigned char *pucNextPos = 0;
	unsigned int   uiNextLen = 0;
	
	switch(s_uiStep){
		case 0:
			memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
			snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, \
				"<iq id=\"_xmpp_bind1\" type=\"set\"><bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"><resource>%s</resource></bind></iq>",\
				pstCtx->pcRes);
      s_uiStep = 1;
      iRet = XS_CONTINUE;
    case 1:
			iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 > iRet){
        if(XS_TCP_BUSY == iRet){
          iRet = XS_CONTINUE;
        }else{
          iRet = XS_FAILURE;
        }
      }else if(0 < iRet){
        s_uiStep = 2;
        iRet = XS_CONTINUE;
      }
			break;
		case 2:
			iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL, pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
			if(0 < iRet){
				pstCtx->uiRLen += iRet;

				iRet = check_xmpp_xml(0, pstCtx->pucRBuf, pstCtx->uiRLen, &pucNextPos, &uiNextLen);
				if(XS_OK == iRet || XS_XML_MUX_PACKAGE == iRet){
					if(0 != strstr((char *)pstCtx->pucRBuf, "result")){
						iRet = XS_OK;
					}else{
						iRet = XS_XML_LOGIN_FAILURE;
					}
				}
			}else if(XS_TCP_BUSY == iRet){
				iRet = XS_CONTINUE;
			}else{
				iRet = XS_FAILURE;
			}
			break;
	}
	if(0 > iRet || XS_OK == iRet){
		s_uiStep = 0;
    pstCtx->uiRLen = 0;
    memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
	}
	return iRet;
}

static int xmpp_start_session(xsCtx_t *pstCtx)
{
	static int s_uiStep = 0;
	int iRet = XS_FAILURE;

	unsigned char *pucNextPos = 0;
	unsigned int   uiNextLen = 0;
	
	switch(s_uiStep){
		case 0:
      if(0 == g_aucMsgId[1]){
    		gs_iRand++;
    		srand(gs_iRand);
    		snprintf((char *)g_aucMsgId, XS_MSG_ID_SIZE, "xs_id_%d", rand());
    	}
			memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
			snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, \
				"<iq id='mq_session_%s' type='set'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>", g_aucMsgId);
      s_uiStep = 1;
      iRet = XS_CONTINUE;
     case 1:
      iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 > iRet){
        if(XS_TCP_BUSY == iRet){
          iRet = XS_CONTINUE;
        }else{
          iRet = XS_FAILURE;
        }
      }else if(0 < iRet){
        s_uiStep = 2;
        iRet = XS_CONTINUE;
      }
			break;
		case 2:
			iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL, pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
			if(0 < iRet){
				pstCtx->uiRLen += iRet;
				iRet = check_xmpp_xml(0, pstCtx->pucRBuf, pstCtx->uiRLen, &pucNextPos, &uiNextLen);
				if(XS_OK == iRet || XS_XML_MUX_PACKAGE == iRet){
					if(0 != strstr((char *)pstCtx->pucRBuf, "result")){
						xs_print("Session establishment successful\n");
						iRet = XS_CONTINUE;
            s_uiStep = 3;
					}else{
						iRet = XS_XML_LOGIN_FAILURE;
						xs_print("Session establishment failure\n");
					}
				}
			}else if(XS_TCP_BUSY == iRet){
				iRet = XS_CONTINUE;
			}else{
				iRet = XS_FAILURE;
			}
			break;
    case 3:
      memset(pstCtx->pucSBuf, 0, pstCtx->uiSsize);
		  snprintf((char *)pstCtx->pucSBuf, pstCtx->uiSsize, "<presence/>");
      s_uiStep = 4;
      iRet = XS_CONTINUE;
    case 4:
	   iRet = pstCtx->pfTcpSend(pstCtx->ucSSL, pstCtx->pucSBuf, strlen((char *)pstCtx->pucSBuf));
      if(0 > iRet){
        if(XS_TCP_BUSY == iRet){
          iRet = XS_CONTINUE;
        }else{
          iRet = XS_FAILURE;
        }
      }else if(0 < iRet){
        iRet = XS_XML_LOGIN_SUCCESS;
      }
      break;
      /*
    case 5:
      iRet = pstCtx->pfTcpRecv(pstCtx->ucSSL, pstCtx->pucRBuf+pstCtx->uiRLen, pstCtx->uiRSize-pstCtx->uiRLen);
			if(0 < iRet){
        iRet = XS_XML_LOGIN_SUCCESS;
      }else if(XS_TCP_BUSY == iRet){
				iRet = XS_CONTINUE;
			}else{
				iRet = XS_FAILURE;
			}
      break;
      */
	}
	if(0 > iRet || XS_XML_LOGIN_SUCCESS == iRet){
		s_uiStep = 0;
    pstCtx->uiRLen = 0;
    memset(pstCtx->pucRBuf, 0, pstCtx->uiRSize);
	}
	return iRet;
}

#define	 XMPP_XML_VERSION_FLAG  "<?xml"

#define	 XMPP_CHAT_START_TAG		"<stream:stream"
enum{
	NORMAL_TAG = 0,
	START_TAG,
	VERSION_FLAG,

}XMPP_TAG;

static int check_xmpp_xml(unsigned char *pucTag, unsigned char *pucData, unsigned int uiLen, unsigned char **pucStazaData, unsigned int *puiStazaLen)
{
	int iRet = XS_XML_NOT_COMPLETE;
	unsigned int uiPos = 0;
	unsigned int uiEPos = 0, uiOkFlag = 0;
	unsigned char aucETag[32] = {0}; /* End tag */
	unsigned char aucSTag[32] = {0}; /* Start tag */
	unsigned char i = 0, j = 0, ucTagFlag = 0xFF;
  short sStartFlag = -1;

  *pucStazaData = 0;
	*puiStazaLen = 0;
  
	if(!pucData){
		return XS_PARA_ERR;
	}
  
	if(15 > uiLen){
		return XS_XML_NOT_COMPLETE;
	}
	
	for(uiPos=0; uiPos<uiLen; uiPos++){
		if(-1 == sStartFlag){
      if('<' == pucData[uiPos]){
        sStartFlag = uiPos;
      }
      continue;
    }
		if(0xFF == ucTagFlag){
			if(' ' == pucData[uiPos] || '>' == pucData[uiPos]){
				if(sizeof(aucETag)-1 < uiPos+1){
					break;
				}
				memcpy(aucSTag, pucData+sStartFlag, uiPos);
        if(pucTag){
          memcpy(pucTag, aucSTag, uiPos);
        }
				//xs_print("StartTag:%s\n", aucSTag);
				if(0 == strncmp((char *)aucSTag, XMPP_XML_VERSION_FLAG, strlen(XMPP_XML_VERSION_FLAG))){
					ucTagFlag = VERSION_FLAG;
				}else if(0 == strncmp((char *)aucSTag, XMPP_CHAT_START_TAG, strlen(XMPP_CHAT_START_TAG))){
					ucTagFlag = START_TAG;
				}else{
					aucETag[0] = '<';
					aucETag[1] = '/';
					for(i=sStartFlag+1, j=2; i<uiPos; i++, j++){
						aucETag[j] = pucData[i];
					}
					aucETag[j++] = '>';
					ucTagFlag = NORMAL_TAG;
					//xs_print("Endtag:%s\n", aucETag);
				}
			}
			continue;
		}

		switch(ucTagFlag){
			case START_TAG:
				if('>' == pucData[uiPos]){
					uiEPos = uiPos;
					uiEPos += 1;
				}
				break;
			case VERSION_FLAG:
				if('?' == pucData[uiPos] && '>' == pucData[uiPos+1]){
					uiEPos = uiPos+1;
					uiEPos += 1;
				}
				break;
			case NORMAL_TAG:
				if(aucETag[uiOkFlag] == pucData[uiPos]){
					uiOkFlag++;
					if(uiOkFlag == strlen((char *)aucETag)){
						uiEPos = uiPos;
						uiEPos += 1;
					}
				}else{
					uiOkFlag = 0;
          if('/' == pucData[uiPos] && '>' == pucData[uiPos+1] && 0 == pucData[uiPos+2]){
  					uiEPos = uiPos+1;
  					uiEPos += 1;
  				}
				}
				break;
			default:
				break;
		}
		if(uiEPos){
			if(uiEPos < uiLen){
				*pucStazaData = (unsigned char *)(pucData+uiEPos);
				*puiStazaLen = uiLen - uiEPos;
				iRet = XS_XML_MUX_PACKAGE;
			}else if(uiEPos == uiLen){
				iRet = XS_OK;
			}
		}
	}
	//xs_print("XML Parse ret:%d\n",iRet);
	return iRet;
}

static int get_challenge_text(unsigned char *pcResData, unsigned int uiLen)
{
	unsigned int uiTextLen = 0;
	unsigned int i, uiStag = 0;
	if(!pcResData){
		return XS_PARA_ERR;
	}	

	if(0 == strstr((char *)pcResData, "</challenge>")){
		return XS_XML_ERR;
	}
	for(i=0; i<uiLen; i++){
		if(0 == uiStag){
			if('>' == pcResData[i]){
				uiStag = i;
			}
		}else{
			if('<' == pcResData[i]){
				pcResData[uiTextLen] = 0;
				break;
			}
			pcResData[uiTextLen] = pcResData[i];
			uiTextLen++;
		}
	}
	xs_print("challenge text:%s\n\r", pcResData);
	return uiTextLen;
}

const char acMsgType[][12] = {{11}, {"type=\"chat\""}};
const char acBodyTag[][7] = {{6}, {"<body>"}};
const char acMsgEndTag[][11] = {{10}, {"</message>"}};
const char acMsgIdTag[][5] = {{4}, {"id=\""}};
const char acMsgFromTag[][7] = {{6}, {"from=\""}};

static int get_xmpp_message(xsMsg_t *pstMsg, unsigned char *pucInData, unsigned int uiInLen)
{
	int iRet = XS_XML_NOT_COMPLETE;
	unsigned short usMsgLen = 0, iPos=0;
  unsigned char b=0, c=0, e=0, f=0;
  unsigned char *pucData = 0;
  unsigned char ucCh = 0, ucEscape = 0;

	if(!pucInData || !pstMsg){
		return XS_PARA_ERR;
	}
 //xs_print("MIn:%s\n", pucInData);
  pucData = pucInData;
  uiInLen = uiInLen;

  for(iPos=0; iPos<uiInLen; iPos++)
  {
    if(0xff != b){
      if(b != acMsgType[0][0]){
        if(acMsgType[1][b] == pucData[iPos]){
          b++;
    		}else{
          b = 0;
        }
      }
      if(b == acMsgType[0][0]){
        b = 0xff;
        xs_print("Type:%s\n", acMsgType[1]);
      }
    }
    
    if(0xff != e){// get id
      if(e != acMsgIdTag[0][0]){
        if(acMsgIdTag[1][e] == pucData[iPos]){
          e++;
    		}else{
          e = 0;
        }
      }
      
      if(e == acMsgIdTag[0][0]){
        memset(g_aucMsgId, 0, XS_MSG_ID_SIZE);
        iPos++;
    		for(e=0; e<XS_MSG_ID_SIZE; e++){
    			g_aucMsgId[e] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            e = 0xff;
            xs_print("S-ID:%s\n", g_aucMsgId);
    				break;
    			}
    		}
      }
    }

    if(0xff != f){ // get jid
      if(f != acMsgFromTag[0][0]){
        if(acMsgFromTag[1][f] == pucData[iPos]){
          f++;
    		}else{
          f = 0;
        }
      }

      if(f == acMsgFromTag[0][0]){
        iPos++;
        memset(pstMsg->aucJid, 0, sizeof(pstMsg->aucJid));
    		for(f=0; f<sizeof(pstMsg->aucJid); f++){
    			pstMsg->aucJid[f] = pucData[iPos++];
          if(0x22 == pucData[iPos] || '/' == pucData[iPos]){
            f = 0xff;
            xs_print("JID :%s\n", pstMsg->aucJid);
    				break;
    			}
    		}
      }
    }
    
    if(0xff != b){
      continue;
    }
    
    if(c != acBodyTag[0][0]){
      if(acBodyTag[1][c] == pucData[iPos]){
        c++;
  		}else{
        c = 0;
      }
      continue;
    }

    for(usMsgLen=0; iPos<uiInLen; iPos++){
      if('<' == pucData[iPos] || XS_MAX_MSG_SIZE == usMsgLen){
        c = 0xff;
        pstMsg->uiMsgLen = usMsgLen;
        pstMsg->ucFlag = XS_DATA;
        iRet = XS_OK;
        break;
      }
			if(1 == ucEscape){
				if( ';' == pucData[iPos]){
					if(ucCh){
						pstMsg->aucMsgData[usMsgLen++] = ucCh;
						ucCh = 0;
					}
					ucEscape = 0;
				}
				continue;
			}
			if( '&' == pucData[iPos]){
				ucEscape = 1;
				ucCh = pucData[iPos++];
				switch(ucCh){
					case 'a':
						ucCh = pucData[iPos++];
						if('m' == ucCh){
							ucCh = 0x26; // &
						}else if('p' == ucCh){
							ucCh = 0x27; // '
						}
						break;
					case 'l':
						ucCh = 0x3C;   // <
						break;
					case 'g':
						ucCh = 0x3E;   // >
						break;
					case 'q':
						ucCh = 0x22;   // "
						break;
				}
				continue;
			}
			pstMsg->aucMsgData[usMsgLen++] = pucData[iPos];
		}
    break;
  }
  return iRet;
}

const char acBCfgTag[][11] = {{10}, {"baudrate=\""}};
const char acSCfgTag[][10] = {{9},  {"stopbit=\""}};
const char acPCfgTag[][9] =  {{8},  {"parity=\""}};
const char acFCfgTag[][11] = {{10}, {"flowctrl=\""}};
const char acDCfgTag[][10] = {{9}, {"databit=\""}};
const char acMCfgTag[][9] = {{8}, {"format=\""}};

const char acCfgMsnTag[][6] ={{5},  {"mSn=\""}};
const char acCfgDsnTag[][6] = {{5},  {"dSn=\""}};
const char acCfgCmdTag[][6] = {{5}, {"cmd=\""}};
const char acCfgCmdVTag[][7] = {{6},  {"para=\""}};

#if 0
static const char *pstTestPre = "<presence type=\"set\" id=\"lomo_1714825882\" from=\"lomo@ghldbgsrv/lomo\" to=\"test1@ghldbgsrv/lomo\"><config xmlns=\"lomo:resconfig\">"
                                "<cmd xmlns=\"lomo:cmd\">10</cmd><status>NO cfg</status>"
                                "<com baudrate=\"115200\" stopbit=\"1\" parity=\"2\" flowctrl=\"3\" databit=\"8\" no=\"1\" format=\"1\"/>"
                                "<master mSn=\"lomo_wh\"/><dest dSn=\"test2\"/></config></presence>";

<message id="nwQKc-5" to="xssl2001@gmail.com" type="chat" from="mqbest2000@gmail.com/Smack0FAAC18A">
  <lomo xmlns="lomo:cmd" cmd="4" para="1"/>
  <nos:x value="disabled" xmlns:nos="google:nosave"/>
  <arc:record otr="false" xmlns:arc="http://jabber.org/protocol/archive"/>
</message>

<message id="nwQKc-7" to="xssl2001@gmail.com" type="chat" from="mqbest2000@gmail.com/Smack0FAAC18A">
<lomo xmlns="lomo:cmd" cmd="1">
<com baudrate="115200" stopbit="1" parity="0" flowctrl="0" no="1" databit="8"/>
<master mSn="lomo_wh"/>
<dest dSn="test2"/>

</lomo><nos:x value="disabled" xmlns:nos="google:nosave"/><arc:record otr="false" xmlns:arc="http://jabber.org/protocol/archive"/></message>

#endif

static int get_lomo_cmd(xsPre_t *pstPre, xsUserCfg_t *pstCfg, unsigned char *pucInData, unsigned int uiInLen)
{
	int iRet = XS_OK;
	unsigned short iPos=0;
  unsigned char b=0, c=0, d=0, 
                e=0, f=0, h=0, 
                i=0, j=0, k=0, l=0, 
                m=0, n=0;
  unsigned char *pucData = 0;

  char acValue[8] = {0};
  if(!pstPre || !pstCfg || !pucInData){
    return XS_FAILURE;
  }
  //xs_print("CIn:%s\n", pucInData);
  
  pucData = pucInData;
  pstCfg->ucCmd = 0xFF;
  memset(pstCfg->aucCmdValue, 0, sizeof(pstCfg->aucCmdValue));
  for(iPos=0; iPos<uiInLen; iPos++)
  {    
    if(0xff != b){// get id
      if(b != acMsgIdTag[0][0]){
        if(acMsgIdTag[1][b] == pucData[iPos]){
          b++;
    		}else{
          b = 0;
        }
      }
      
      if(b == acMsgIdTag[0][0]){
        memset(g_aucMsgId, 0, XS_MSG_ID_SIZE);
        iPos++;
    		for(b=0; b<XS_MSG_ID_SIZE; b++){
    			g_aucMsgId[b] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            b = 0xff;
            xs_print("S-ID     :%s\n", g_aucMsgId);
    				break;
    			}
    		}
      }
    }

    if(0xff != c){ // get jid
      if(c != acMsgFromTag[0][0]){
        if(acMsgFromTag[1][c] == pucData[iPos]){
          c++;
    		}else{
          c = 0;
        }
      }

      if(c == acMsgFromTag[0][0]){
        iPos++;
        memset(pstPre->aucJid, 0, sizeof(pstPre->aucJid));
    		for(c=0; c<sizeof(pstPre->aucJid); c++){
    			pstPre->aucJid[c] = pucData[iPos++];
          if(0x22 == pucData[iPos] || '/' == pucData[iPos]){
            c = 0xff;
            xs_print("JID      :%s\n", pstPre->aucJid);
    				break;
    			}
    		}
      }
    }

    if(0xff != d){ // get cfg baudrate
      if(d != acBCfgTag[0][0]){
        if(acBCfgTag[1][d] == pucData[iPos]){
          d++;
    		}else{
          d = 0;
        }
      }
      if(d == acBCfgTag[0][0]){
        iPos++;
        memset(acValue, 0, sizeof(acValue));
    		for(d=0; d<sizeof(acValue); d++){
    			acValue[d] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            d = 0xff;
            pstCfg->stCom.baudrate = atoi(acValue);
            xs_print("Baudrate :%d\n", pstCfg->stCom.baudrate);
    				break;
    			}
    		}
      }
    }

    if(0xff != e){ // get cfg stipbit
      if(e != acSCfgTag[0][0]){
        if(acSCfgTag[1][e] == pucData[iPos]){
          e++;
    		}else{
          e = 0;
        }
      }
      if(e == acSCfgTag[0][0]){
        iPos++;
        memset(acValue, 0, sizeof(acValue));
    		for(e=0; e<sizeof(acValue); e++){
    			acValue[e] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            e = 0xff;
            pstCfg->stCom.stopbit = atoi(acValue);
            xs_print("StopBit  :%d\n", pstCfg->stCom.stopbit);
    				break;
    			}
    		}
      }
    }

    if(0xff != f){ // get cfg parity
      if(f != acPCfgTag[0][0]){
        if(acPCfgTag[1][f] == pucData[iPos]){
          f++;
    		}else{
          f = 0;
        }
      }
      if(f == acPCfgTag[0][0]){
        iPos++;
        memset(acValue, 0, sizeof(acValue));
    		for(f=0; f<sizeof(acValue); f++){
    			acValue[f] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            f = 0xff;
            pstCfg->stCom.parity = atoi(acValue);
            xs_print("Parity   :%d\n", pstCfg->stCom.parity);
    				break;
    			}
    		}
      }
    }

    if(0xff != h){ // get cfg flowctrl
      if(h != acFCfgTag[0][0]){
        if(acFCfgTag[1][h] == pucData[iPos]){
          h++;
    		}else{
          h = 0;
        }
      }
      if(h == acFCfgTag[0][0]){
        iPos++;
        memset(acValue, 0, sizeof(acValue));
    		for(h=0; h<sizeof(acValue); h++){
    			acValue[h] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            h = 0xff;
            pstCfg->stCom.flowctrl= atoi(acValue);
            xs_print("Flowctrl :%d\n", pstCfg->stCom.flowctrl);
    				break;
    			}
    		}
      }
    }

    if(0xff != i){ // get cfg databit
      if(i != acDCfgTag[0][0]){
        if(acDCfgTag[1][i] == pucData[iPos]){
          i++;
    		}else{
          i = 0;
        }
      }
      if(i == acDCfgTag[0][0]){
        iPos++;
        memset(acValue, 0, sizeof(acValue));
    		for(i=0; i<sizeof(acValue); i++){
    			acValue[i] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            i = 0xff;
            pstCfg->stCom.databit = atoi(acValue);
            xs_print("Databit  :%d\n", pstCfg->stCom.databit);
    				break;
    			}
    		}
      }
    }

    if(0xff != j){ // get cfg databit
      if(j != acMCfgTag[0][0]){
        if(acMCfgTag[1][j] == pucData[iPos]){
          j++;
    		}else{
          j = 0;
        }
      }
      if(j == acMCfgTag[0][0]){
        iPos++;
        memset(acValue, 0, sizeof(acValue));
    		for(j=0; j<sizeof(acValue); j++){
    			acValue[j] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            j = 0xff;
            pstCfg->ucDataFormat = atoi(acValue);
            xs_print("Format   :%d\n", pstCfg->ucDataFormat);
    				break;
    			}
    		}
      }
    }

    if(0xff != k){ // get master id
      if(k != acCfgMsnTag[0][0]){
        if(acCfgMsnTag[1][k] == pucData[iPos]){
          k++;
    		}else{
          k = 0;
        }
      }
      if(k == acCfgMsnTag[0][0]){
        iPos++;
        memset(pstCfg->acMaster, 0, sizeof(pstCfg->acMaster));
    		for(k=0; k<sizeof(pstCfg->acMaster)-1; k++){
    			pstCfg->acMaster[k] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            k = 0xff;
            xs_print("MasterID :%s\n", pstCfg->acMaster);
    				break;
    			}
    		}
      }
    }

    if(0xff != l){ // get device peer id
      if(l != acCfgDsnTag[0][0]){
        if(acCfgDsnTag[1][l] == pucData[iPos]){
          l++;
    		}else{
          l = 0;
        }
      }
      if(l == acCfgDsnTag[0][0]){
        iPos++;
        memset(pstCfg->acDevPeer, 0, sizeof(pstCfg->acDevPeer));
    		for(l=0; l<sizeof(pstCfg->acDevPeer)-1; l++){
    			pstCfg->acDevPeer[l] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            l = 0xff;
            xs_print("DevPeerID:%s\n", pstCfg->acDevPeer);
    				break;
    			}
    		}
      }
    }

    if(0xff != m){ // get cmd
      if(m != acCfgCmdTag[0][0]){
        if(acCfgCmdTag[1][m] == pucData[iPos]){
          m++;
    		}else{
          m = 0;
        }
      }
      if(m == acCfgCmdTag[0][0]){
        iPos++;
        memset(acValue, 0, sizeof(acValue));
    		for(m=0; m<sizeof(acValue); m++){
    			acValue[m] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            m = 0xff;
            pstPre->ucFlag = XS_PRE_CMD;
            pstCfg->ucCmd = atoi(acValue);
            xs_print("UserCmd  :%d\n", pstCfg->ucCmd);
    				break;
    			}
    		}
      }
    }

    if(0xff != n){ // get cfg cmd value
      if(n != acCfgCmdVTag[0][0]){
        if(acCfgCmdVTag[1][n] == pucData[iPos]){
          n++;
    		}else{
          n = 0;
        }
      }
      if(n == acCfgCmdVTag[0][0]){
        iPos++;
    		for(n=0; n<sizeof(pstCfg->aucCmdValue)-1; n++){
    			pstCfg->aucCmdValue[n] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            n = 0xff;
            xs_print("CmdValue :%s\n", pstCfg->aucCmdValue);
    				break;
    			}
    		}
      }
    }    
  }
  return iRet;
}


const char acPreType[][7] = {{6}, {"type=\""}};

static int get_xmpp_presence(xsPre_t *pstPre, unsigned char *pucInData, unsigned int uiInLen)
{
	int iRet = XS_OK;
	unsigned short iPos=0;
  unsigned char a=0, c=0;
  unsigned char *pucData = 0;
  if(!pstPre || !pucInData){
    return XS_FAILURE;
  }
  //xs_print("PIn:%s\n", pucInData);
  pucData = pucInData;  
  for(iPos=0; iPos<uiInLen; iPos++)
  {
    if('>' == pucData[iPos]){
      break;
    }
    
    if(0xff != a){ // get type
      if(a != acPreType[0][0]){
        if(acPreType[1][a] == pucData[iPos]){
          a++;
    		}else{
          a = 0;
        }
      }
      if(a == acPreType[0][0]){
        iPos++;
    		for(a=0; a<XS_PRE_SIZE; a++){
    			pstPre->aucStatType[a] = pucData[iPos++];
          if(0x22 == pucData[iPos]){
            a = 0xff;
            xs_print("PreType  :%s\n", pstPre->aucStatType);
    				break;
    			}
    		}
      }
    }
    
    if(0xff != c){ // get jid
      if(c != acMsgFromTag[0][0]){
        if(acMsgFromTag[1][c] == pucData[iPos]){
          c++;
    		}else{
          c = 0;
        }
      }

      if(c == acMsgFromTag[0][0]){
        iPos++;
    		for(c=0; c<sizeof(pstPre->aucJid); c++){
    			pstPre->aucJid[c] = pucData[iPos++];
          if(0x22 == pucData[iPos] || '/' == pucData[iPos]){
            c = 0xff;
            pstPre->ucFlag = XS_PRE_STATE;
            xs_print("JID      :%s\n", pstPre->aucJid);
    				break;
    			}
    		}
      }
    }   
  }
  return iRet;
}


